﻿using System;
using System.Linq;

using Buddy.BehaviorTree;
using Buddy.Common;
using Buddy.CommonBot;
using Buddy.Swtor;
using Buddy.Swtor.Objects;

using WingIt;
using WingIt.Dynamics;
using WingIt.Routines;
using WingIt.Routines.Mirrors;

using Action = Buddy.BehaviorTree.Action;

namespace WingIt.Routines
{//by protpally
    [RevisionControlId("$Id: Bodyguard_CombatMedic.cs 691 2012-08-13 12:39:26Z Chinajade $")]
    public class MercenaryBodyguard_CommandoCombatMedic : MirrorRoutine
    {
        // MAINTAINERS NOTES:
        // * You will notice that lambda expression argument names are unique (e.g., "darkWardOn", "darkWardWhen", "joltWhen"),
        //   instead of generic (e.g., "ctx", "ret", "on", "doWhen", "castWhen").  PLEASE honor this convention!
        //   This allows us to quickly localize problems when looking at user's logs.  When the BehaviorTree encounters an exception
        //   (e.g., "object not found"), the location where an exception is thrown is identifiable only through the name
        //   of the lambda expression argument.  Such is the nature of BehaviorTrees.

        //protected static TorCharacter HealTarget { get { return ((Me.IsInParty() && (HealTarget != null)) ? HealTarget : Tank ); } }
        [Behavior(BehaviorType.Pull)]
        [Class(CharacterClass.BountyHunter, AdvancedClass.Mercenary, SkillTreeId.MercenaryBodyguard)]
        [Class(CharacterClass.Trooper, AdvancedClass.Commando, SkillTreeId.CommandoCombatMedic)]
        public static Composite MercenaryBodyguard_CommandoCombatMedic_Pull()
        {
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                CreateBTPS.BWcoreFixup_WaitForHarvestComplete(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                new Decorator(doWhenInParty => Me.IsInParty(), new Action(alwaysSucceed => RunStatus.Success)),
                new Decorator(doWhenNotInParty => !Me.IsInParty(), MercenaryBodyguard_CommandoCombatMedic_Combat())
            );
        }

        [Behavior(BehaviorType.Combat)]
        [Class(CharacterClass.BountyHunter, AdvancedClass.Mercenary, SkillTreeId.MercenaryBodyguard)]
        [Class(CharacterClass.Trooper, AdvancedClass.Commando, SkillTreeId.CommandoCombatMedic)]
        public static Composite MercenaryBodyguard_CommandoCombatMedic_Combat()
        {
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                CreateBTPS.StopWithinRangeAndLoS(target => MyTarget, Global.Distance.Ranged),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                new Decorator(whenLowResources => Resource < 25,
                    new Action(burnPhaseOff => LazyRaider.BurnPhaseOff())
                ),

                #region Burn Phase
                #endregion

                #region Lazyraiderish stuff - works with combat movement off
                new Decorator(whenMoving => Me.IsMoving,
                    new PrioritySelector(
                        Cast("Trauma Probe", traumaProbeOn => Tank, tramaProbeWhen => !Tank.HasMirrorBuffStacks("Trauma Probe", 1, b => b.TimeLeft > TimeSpan.FromSeconds(4))),
                        BuffSelf("Reactive Shield", reactiveShieldWhen => Me.HealthPercent < 40),
                        Cast("Adrenaline Rush", adrenalineRushWhen => Me.HealthPercent <= 60),
                        Cast("Concussion Charge", concussionChargeWhen => Resource >= 84 && Me.MobCountAround(0.4f, Mob => Mob.IsHostile) >= 2),
                        Cast("Diversion"),
                        Cast("Cryo Grenade", cryoGrenadeWhen => Global.RequiresCrowdControl),
                        new Decorator(healWhen => HealTarget != null,
                            new PrioritySelector(
                                Cast("Bacta Infusion", bactaInfusionOn => HealTarget, bactaInfusionWhen => HealTarget.HealthPercent <= Global.Health.Mid),
                                Cast("Hammer Shot", hammerShotOn => HealTarget, hammerShotWhen => HealTarget != Me)
                                ))
                    )
                ),
                #endregion

                // General
                BuffSelf("Reactive Shield", reactiveShieldWhen => Me.HealthPercent < 40),
                Cast("Adrenaline Rush", adrenalineRushWhen => Me.HealthPercent <= 60),
                Cast("Supercharge Cells", superchargeCellsWhen => Me.HasMirrorBuffStacks("Supercharge", 30) && Me.InCombat),
                Cast("Diversion", diversionWhen => Me.MobCountAttacking() >= 2),
                Cast("Trauma Probe", traumaProbeOn => Tank, traumaProbeWhen => !Tank.HasMirrorBuffStacks("Trauma Probe", 1, b => b.TimeLeft > TimeSpan.FromSeconds(4))),

                // CC
                Cast("Concussion Charge", concussionChargeWhen => Resource >= 84 && Me.MobCountAround(Global.Distance.MeleeAoE, Mob => Mob.IsHostile) >= 3),
                Cast("Cryo Grenade", cryoGrenadeWhen => Global.RequiresCrowdControl),

                // Damage Rotation - if NOT in Party OR Resource and Health of Partymembers is high enough!
                #region SoloMode
                new Decorator(whenNoSeriousHealsNeeded => TargetSelect.ForHeal(true, m => m.HealthPercent < 90) == null,
                        new PrioritySelector
                        (
                            Cast("Sticky Grenade", stickyGrenadeWhen => MyTarget.MobCountAround(Global.Distance.MeleeAoE) >= 3),
                            Cast("Hammer Shot", hammerShotWhen => Resource < 75 && !(LazyRaider.IsBurnPhaseEnabled || MeHasConsumableBuff("Critical Boost") || MeHasConsumableBuff("Power Boost"))),
                            Cast("Concussion Charge", concussionChargeWhen => Resource >= 84 && Me.MobCountAround(0.4f, Mob => Mob.IsHostile) >= 2),
                            Cast("Stockstrike", stockstrikeWhen => Resource >= 84 && MyTarget.IsInRange(0.8f)),
                            Cast("High Impact Bolt"),
                            Cast("Explosive Round", explosiveRoundWhen => Resource >= 84),
                            Cast("Charged Bolts", chargedBoltsWhen => Me.CanMirrorCast("Charged Bolts", MyTarget)),
                            Cast("Hammer Shot")
                        )
                    ),
                #endregion

                // Burst-Heal Rotation
                new Decorator(whenSuperchargeCells => Me.HasMirrorBuff("Supercharge Cells") && (HealTarget != null),
                    new PrioritySelector(
                        Cast("Bacta Infusion", bactaInfusionOn => HealTarget, bactaInfusionWhen => HealTarget.HealthPercent <= Global.Health.Low),
                        Cast("Advanced Medical Probe", advancedMedicalProbeOn => HealTarget, AdvMedProbeWhen => HealTarget.HealthPercent <= Global.Health.Mid && Resource >= 77),
                        Cast("Medical Probe", medicalProbeOn => HealTarget, medProbeWhen => HealTarget.HealthPercent <= Global.Health.High && Resource >= 77),
                        Cast("Hammer Shot", hammerShotOn => HealTarget, hammerShotWhen => (HealTarget != Me) && HealTarget.HealthPercent >= Global.Health.High)
                    )
                ),

                // Heal Rotation
                new Decorator(healWhen => HealTarget != null,
                    new PrioritySelector(
                        Cast("Bacta Infusion", bactaInfusionOn => HealTarget, bactaInfusionWhen => HealTarget.HealthPercent <= Global.Health.Low),
                        CastOnGround("Kolto Bomb", koltoBombOn => Me.PartyPlayers().FirstOrDefault(p => p.HealthPercent <= Global.Health.Mid).Position, koltoBombWhen => Me.PartyPlayers(p => p.HealthPercent <= Global.Health.Mid && p.IsInRange(1f)).Count() >= 3),//AoE Heal
                        Cast("Advanced Medical Probe", advancedMedicalProbeOn => HealTarget, AdvMedProbeWhen => HealTarget.HealthPercent <= Global.Health.Mid && Resource >= 77),
                        Cast("Medical Probe", medicalProbeOn => HealTarget, medProbeWhen => HealTarget.HealthPercent <= Global.Health.High && Resource >= 77),
                        Cast("Hammer Shot", hammerShotOn => HealTarget, hammerShotWhen => (HealTarget != Me) && HealTarget.HealthPercent < Global.Health.Strong),
                        Cast("Hammer Shot", hammerShotOn => HealTarget, hammerShotWhen => (HealTarget == Tank) && !Me.HasMirrorBuffStacks("Supercharge", 30, b => b.TimeLeft > TimeSpan.FromSeconds(4)) && Me.HasMirrorAbility("Supercharge Cells"))
                        )),
                        
                // Movement
                CreateBTPS.MoveWithinRangeAndLoS(target => MyTarget, Global.Distance.Ranged)

            );
        }

        [Behavior(BehaviorType.OutOfCombat)]
        [Class(CharacterClass.BountyHunter, AdvancedClass.Mercenary, SkillTreeId.MercenaryBodyguard)]
        [Class(CharacterClass.Trooper, AdvancedClass.Commando, SkillTreeId.CommandoCombatMedic)]
        public static Composite MercenaryBodyguard_CommandoCombatMedic_OutOfCombat()
        {
            // NB: Apparently, BWcore will call this routine when in combat on occasion.  It is also called while we're pulling.
            return new PrioritySelector(
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),
                new Decorator(oocBuffWhen => !Me.IsMounted,
                    new PrioritySelector(
                        BuffSelf("Combat Support Cell"),
                        BuffSelf("Armor-piercing Cell", ArmorpiercingCellWhen => !Me.HasMirrorAbility("Combat Support Cell")),
                        BuffSelf("Plasma Cell", PlasmaCellWhen => !Me.HasMirrorAbility("Combat Support Cell") && !Me.HasMirrorAbility("Armor-piercing Cell")),
                        // Heal slacking party members, after battle...
                        // NB: We only need to do this when in a party, because our Rejuvenation will take care of the needs
                        // of self and companion.
                        new Decorator(whenPartyNeedsHeal => Me.IsInParty() && (HealTarget != null),
                            MercenaryBodyguard_CommandoCombatMedic_Combat()),
                        Cast("Hammer Shot", hammerShotOn => Tank, hammerShotWhen => Me.IsInParty() && !Me.HasMirrorBuffStacks("Supercharge", 30, b => b.TimeLeft > TimeSpan.FromSeconds(4)) && Me.HasMirrorAbility("Supercharge Cells"))
                        ))
                );
        }
    }
}